package cn.wwcyc.controller;

import cn.wwcyc.dao.ModbusDao;
import cn.wwcyc.domain.*;
import cn.wwcyc.exception.WWExceptionEnum;
import cn.wwcyc.mapper.TDjxxMapper;
import cn.wwcyc.mapper.TjDevMapper;
import cn.wwcyc.service.*;
import cn.wwcyc.utils.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.locator.BaseLocator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.bouncycastle.asn1.eac.UnsignedInteger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@RestController
@RequestMapping("/dev")

public class DEVController {

    @Autowired
    TjDevMapper tjDevMapper;
    @Autowired
    TjDwService tjDwService;
    @Autowired
    TjRegService tjRegService;
    @Autowired
    UserService userService;
    @Autowired
    TjDevService tjDevService;


    //此分页函数中的返回对象中不含有单位及类型对象数据
    @RequestMapping("/getpage1")
    public R<IPage<TjDev>> getPage1(
            @RequestParam Integer pagenum,
            @RequestParam Integer pagesize,
            @RequestParam(required = false) Long dwid,
            @RequestParam(required = false) Long devtype,
            @RequestParam(required = false) String devname
    ) {
        LambdaQueryWrapper<TjDev> qw = new LambdaQueryWrapper();
        if (!StringUtils.isBlank(devname))
            qw.like(TjDev::getName, devname);
        qw.eq(dwid != null, TjDev::getDwid, dwid);
        qw.eq(devtype != null, TjDev::getDevtype, devtype);
        IPage<TjDev> page = new Page<>(pagenum, pagesize);
        page = tjDevMapper.selectPage(page, qw);
        return R.success(page);
    }

    //此分页函数中的返回对象中含有单位及设备类型对象数据
    @RequestMapping("/getpage")
    public R<IPage<TjDev>> getPage(
            @RequestParam Integer pagenum,
            @RequestParam Integer pagesize,
            @RequestParam(required = false) Long dwid,
            @RequestParam(required = false) Long devtype,
            @RequestParam(required = false) String devname,
            HttpServletRequest request
    ) {
        //计时
        long start = System.currentTimeMillis();
        System.out.println("--------------start:" + start);
//        System.out.println("dwid:" + dwid + "  devtype:" + devtype + "  devname:" + devname);
        IPage<TjDev> page = new Page<>(pagenum, pagesize);
        QueryWrapper<TjDev> qw = new QueryWrapper<>();
        if (!StringUtils.isBlank(devname)) {
            qw.like("name", devname);
        }
        User user = userService.getCurrentUser(request);
        if(dwid == null)
            dwid = user.getDw();

        TjDw tjDw = null;
        if (dwid != null) {
            tjDw = tjDwService.getDwTreeById(dwid);
        }
        List<TjDw> dwlist = new ArrayList<>();
        dwlist = tjDwService.DwTreeToList(dwlist, tjDw);
        List<Long> dwIdList = new ArrayList<>();
        for (TjDw tjDw1 : dwlist) {
            dwIdList.add(tjDw1.getId());
        }
        if (dwIdList.size() > 0) {
            qw.in("dwid", dwIdList);
        }
//        if (dwid != null) {
//            qw.eq("dwid", dwid);
//        }
        if (devtype != null) {
            qw.eq("devtype", devtype);
        }
        long count = tjDevMapper.selectCount(qw);

        page.setTotal(count);
        page.setPages(page.getTotal() % page.getSize() == 0 ? page.getTotal() / page.getSize() : page.getTotal() / page.getSize() + 1);
        if (pagenum > page.getPages()) {
            page.setCurrent(page.getPages());
        }
        if (pagenum < 1) {
            page.setCurrent(1);
        }
        Long beforepageTime = System.currentTimeMillis();
        System.out.println("-------------beforepageTime:" + (beforepageTime-start));
//        System.out.println("pagenum:" + pagenum + "  pagesize:" + pagesize + " current:" + page.getCurrent() + "  size:" + page.getSize() + " pages:" + page.getPages());
        List<TjDev> list = tjDevMapper.selectPagewithObj(page.getCurrent(), page.getSize(), dwIdList, devtype, devname);
        page.setRecords(list);
        Long end = System.currentTimeMillis();
        System.out.println("-------------pageTime:" + (end - beforepageTime));
        System.out.println("---------------------耗时：" + (end - start));
        return R.success(page);
    }

    private String getIp(HttpServletRequest request) {
        String ip = null;
        if (request.getHeader("x-forwarded-for") == null) {
            ip = request.getRemoteAddr();
        } else {
            String xff = request.getHeader("x-forwarded-for");
            if (xff != null && xff.length() != 0) {
                ip = xff.split(",")[0];
            }
        }
        return ip;
    }

    @GetMapping("/getById")
    public R save(@RequestParam Long id) {
        TjDev dev = tjDevMapper.selectById(id);
        return R.success(dev);
    }

    @PostMapping("/save")
    public R save(@RequestBody TjDev dev) {
        tjDevMapper.insert(dev);
        return R.success();
    }
    @GetMapping("/copy")
    public R copy(@RequestParam Long id, @RequestParam Integer count) {
        tjDevService.copy(id, count);
//        tjDevMapper.insert(dev);
        return R.success();
    }

    @PostMapping("/edit")
    public R edit(@RequestBody TjDev dev) {
        tjDevMapper.updateById(dev);
        return R.success();
    }

    //
    @DeleteMapping
    public R del(Integer id) {
        tjDevMapper.deleteById(id);
        return R.success();
    }

    @PostMapping("delbatch")
    public R delbatch(@RequestBody List<TjDev> list) {
        for (TjDev dev : list) {
            Long id = dev.getId();
            tjDevMapper.deleteById(id);
        }
        return R.success();
    }

    @Deprecated
    @GetMapping("/sendyewu")
    public R sendyewu(
            @RequestParam Long devid,
            @RequestParam Long yewuid,
            @RequestParam(required = false) String content,
            @RequestParam(required = false) Boolean bvalue
    ) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        TjDev dev = tjDevMapper.selectById(devid);
        TjReg reg = tjRegService.getObjById(yewuid);
        String ip = dev.getIp();
//        DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED
//        DataType.FOUR_BYTE_FLOAT
        ModbusMaster master = ModbusDao.getMaster(ip);
        if (reg.getSpecialtypeObj().getFuncode() == 5 ) {
            ModbusDao.setCoilStatus(ip, 1, Integer.parseInt(reg.getLocation()), bvalue);
        }else if (reg.getSpecialtypeObj().getFuncode() == 6 ) {
            ModbusDao.writeSingleRegister(ip, 1, Integer.parseInt(reg.getLocation()), Short.parseShort(content));
        } else if (reg.getSpecialtypeObj().getFuncode() == 1005 ) {
            int v = Integer.parseInt(content);
            System.out.println("-----------------" + v);
            ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()), DataType.FOUR_BYTE_INT_SIGNED, Integer.parseInt(content));
        } else if (reg.getSpecialtypeObj().getFuncode() == 1007 ) {
            ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()), DataType.FOUR_BYTE_INT_SIGNED_SWAPPED, Integer.parseInt(content));
        } else if (reg.getSpecialtypeObj().getFuncode() == 1025 ) {
            ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()), DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED, Integer.parseInt(content));
        } else if (reg.getSpecialtypeObj().getFuncode() == 1008 ) {
            ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()), DataType.FOUR_BYTE_FLOAT, Float.parseFloat(content));
        }
        return R.success();
    }

    @Deprecated
    @PostMapping("/sendbatchyewu")
    public R sendbatchyewu(
            @RequestBody BatchYewuDTO batchYewuDTO
    ) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        System.out.println("----------------------");
        System.out.println(batchYewuDTO);
        List<Long> devids = batchYewuDTO.getDevids();
        Long yewutypeid = batchYewuDTO.getYewutypeid();
        String content = batchYewuDTO.getContent();
        Boolean bvalue = batchYewuDTO.getBvalue();

        for(int i=0; i<devids.size(); i++){
            TjDev dev = tjDevMapper.selectById(devids.get(i));
            List<TjReg> regList = tjRegService.ListBydevandyewutypeid(devids.get(i), yewutypeid);
            System.out.println( "=======================regList:");
            System.out.println(regList);
            String ip = dev.getIp();
            if(regList == null)
                continue;
            for(TjReg reg: regList){
                ModbusMaster master = ModbusDao.getMaster(ip);
                if (reg.getSpecialtypeObj().getFuncode() == 5 ) {
                    ModbusDao.setCoilStatus(ip, 1, Integer.parseInt(reg.getLocation()), bvalue);
                }else if (reg.getSpecialtypeObj().getFuncode() == 6 ) {
                    ModbusDao.writeSingleRegister(ip, 1, Integer.parseInt(reg.getLocation()), Short.parseShort(content));
                } else if (reg.getSpecialtypeObj().getFuncode() == 1005 ) {
                    int v = Integer.parseInt(content);
                    ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()),  DataType.FOUR_BYTE_INT_SIGNED,Integer.parseInt(content));
                } else if (reg.getSpecialtypeObj().getFuncode() == 1007 ) {
                    ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()), DataType.FOUR_BYTE_INT_SIGNED_SWAPPED, Integer.parseInt(content));
                } else if (reg.getSpecialtypeObj().getFuncode() == 1025 ) {
                    ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()), DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED, Integer.parseInt(content));
                } else if (reg.getSpecialtypeObj().getFuncode() == 1008 ) {
                    ModbusDao.setHoldingRegister(ip, 1, Integer.parseInt(reg.getLocation()), DataType.FOUR_BYTE_FLOAT, Float.parseFloat(content));
                }
            }
        }
        return R.success();
    }


    //0： 线圈 1： 离散 3： 输入 4： 保持

    @GetMapping("/getBoolYewu")
    public R<Boolean> getBoolYewu(@RequestParam Long devid, @RequestParam Long regid)
    {
        TjDev dev = tjDevMapper.selectById(devid);
        TjReg reg = tjRegService.getObjById(regid);
        if(reg.getRegtype() != 1 && reg.getRegtype() != 0){
            return R.error(WWExceptionEnum.YEWU_TYPE_ERROR);
        }
        if(reg.getRegtype() == 0) {
            try {
                Boolean bval = ModbusDao.readCoilStatus(dev.getIp(), 1, Integer.parseInt(reg.getLocation()));
                return R.success(bval);
            } catch (Exception e) {
                return R.error(WWExceptionEnum.MODBUS_ERROR);
            }
        } else if(reg.getRegtype() == 1) {
            try {
                Boolean bval = ModbusDao.readInputStatus(dev.getIp(), 1, Integer.parseInt(reg.getLocation()));
                return R.success(bval);
            } catch (Exception e) {
                return R.error(WWExceptionEnum.MODBUS_ERROR);
            }
        }
        return R.error(WWExceptionEnum.YEWU_TYPE_ERROR);
    }

    @GetMapping("/getNumberYewu")
    public R<Number> getNumberYewu(@RequestParam Long devid, @RequestParam Long regid)
    {
        TjDev dev = tjDevMapper.selectById(devid);
        TjReg reg = tjRegService.getObjById(regid);
        if(reg.getRegtype() != 3 && reg.getRegtype() != 4){
            return R.error(WWExceptionEnum.YEWU_TYPE_ERROR);
        }
        if(reg.getRegtype() == 4) {
            try {
                Number val = ModbusDao.readHoldingRegister(dev.getIp(), 1, Integer.parseInt(reg.getLocation()), reg.getRegdatatp());
                return R.success(val);
            } catch (Exception e) {
                return R.error(WWExceptionEnum.MODBUS_ERROR);
            }
        }else if(reg.getRegtype() == 3){
            try {
                Number val = ModbusDao.readInputRegister(dev.getIp(), 1, Integer.parseInt(reg.getLocation()), reg.getRegdatatp());
                return R.success(val);
            }catch(Exception e){
                return R.error(WWExceptionEnum.MODBUS_ERROR);
            }
        }
        return R.error(WWExceptionEnum.YEWU_TYPE_ERROR);
    }

    @GetMapping("/setBoolYewu")
    public R<Boolean> setBoolYewu(@RequestParam Long devid, @RequestParam Long regid, @RequestParam Boolean bvalue)
    {
        TjDev dev = tjDevMapper.selectById(devid);
        TjReg reg = tjRegService.getObjById(regid);
        if(reg.getRegtype() != 0){
            return R.error(WWExceptionEnum.YEWU_TYPE_ERROR);
        }
        try {
            ModbusDao.setCoilStatus(dev.getIp(), 1, Integer.parseInt(reg.getLocation()), bvalue);
            Boolean bval = ModbusDao.readCoilStatus(dev.getIp(), 1, Integer.parseInt(reg.getLocation()));
            return R.success(bval);
        }catch( Exception e){
            return R.error(WWExceptionEnum.MODBUS_ERROR);
        }
    }

    @GetMapping("/setNumberYewu")
    public R<Number> setNumberYewu(@RequestParam Long devid, @RequestParam Long regid, @RequestParam Number nvalue)
    {
        TjDev dev = tjDevMapper.selectById(devid);
        TjReg reg = tjRegService.getObjById(regid);
        if(reg.getRegtype() != 4){
            return R.error(WWExceptionEnum.YEWU_TYPE_ERROR);
        }
        try {
            if(reg.getRegdatatp()==2 || reg.getRegdatatp()==3 || reg.getRegdatatp()==4 || reg.getRegdatatp()==5 ||reg.getRegdatatp()==8) {
                ModbusDao.setHoldingRegister(dev.getIp(), 1, Integer.parseInt(reg.getLocation()), reg.getRegdatatp(), nvalue);
                Number val = ModbusDao.readHoldingRegister(dev.getIp(), 1, Integer.parseInt(reg.getLocation()), reg.getRegdatatp());
                return R.success(val);
            }
            return R.error(WWExceptionEnum.YEWU_TYPE_ERROR);
        }catch( Exception e){
            return R.error(WWExceptionEnum.MODBUS_ERROR);
        }
    }

//    @Deprecated
//    @GetMapping("/getHoldingBatch")
//    public R<List<UnsignedInteger>> getHoldingBatch(@RequestParam String ip, @RequestParam Integer regtype,@RequestParam Integer startlocation,@RequestParam Integer len) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
////        ModbusMaster master = ModbusDao.getMaster(ip);
//
//        BatchRead<UnsignedInteger> batch = new BatchRead<UnsignedInteger>();
//        Integer i = len;
//        while(i-->0){
//            batch.addLocator(UnsignedInteger.getInstance(startlocation), BaseLocator.holdingRegister(1, startlocation, DataType.TWO_BYTE_INT_UNSIGNED));
//            startlocation++;
//        }
////        batch.addLocator(UnsignedInteger.getInstance(1), BaseLocator.holdingRegister(1, startloaction, DataType.TWO_BYTE_INT_UNSIGNED));
////        batch.addLocator(2, BaseLocator.holdingRegister(1, startloaction, DataType.TWO_BYTE_INT_SIGNED));
//
//        batch.setContiguousRequests(false);
//        ModbusMaster master = ModbusDao.getMaster(ip);
//        BatchResults<UnsignedInteger> response = master.send(batch);
//        List<UnsignedInteger> uiList = new ArrayList<>();
//        for(i=0; i<len; i++){
//            uiList.add((UnsignedInteger) response.getValue(UnsignedInteger.getInstance(i)));
//        }
//        return R.success(uiList);
//    }

    @GetMapping("/getNumberBatch")
    public R<Map<String, List<Number>>> getNumberBatch(@RequestParam String ip, @RequestParam Integer regtype, @RequestParam Integer startlocation, @RequestParam Integer len) throws ModbusInitException, ModbusTransportException, ErrorResponseException {

        //BatchRead<Integer> , BatchResults<Integer>
        // 这2个泛型代表id；并不是从modbus协议中取回的值的类型！！  每个id对应一个保存的位置信息
        //response.getValue(startlocation)中的参数就是这个id泛型，意思是从哪个id对应的modbus位置取值
        BatchRead<String> batch = new BatchRead<>();
        Integer i = len;
        Integer startlocationTmp = startlocation;
        String startStr = startlocation.toString();
        if (regtype == 4) {
            while (i-- > 0 && startlocationTmp <= 65535 ) {
                String strTmp ="U" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.holdingRegister(1, startlocationTmp, DataType.TWO_BYTE_INT_UNSIGNED));
                strTmp ="I" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.holdingRegister(1, startlocationTmp, DataType.TWO_BYTE_INT_SIGNED));
                if(startlocationTmp >= 65535){
                    // 超出65535 跳过4字节读取
                    continue;
                }
                strTmp = "4U" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.holdingRegister(1, startlocationTmp, DataType.FOUR_BYTE_INT_UNSIGNED));
                strTmp = "4I" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.holdingRegister(1, startlocationTmp, DataType.FOUR_BYTE_INT_SIGNED));
                strTmp = "F" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.holdingRegister(1, startlocationTmp, DataType.FOUR_BYTE_FLOAT));
                startlocationTmp++;
            }
        } else if (regtype == 3) {
            while (i-- > 0 && startlocationTmp <= 65535) {
                String strTmp ="U" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.inputRegister(1, startlocationTmp, DataType.TWO_BYTE_INT_UNSIGNED));
                strTmp ="I" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.inputRegister(1, startlocationTmp, DataType.TWO_BYTE_INT_SIGNED));
                if(startlocationTmp >= 65535){
                    // 超出65535 跳过4字节读取
                    continue;
                }
                strTmp = "4U" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.inputRegister(1, startlocationTmp, DataType.FOUR_BYTE_INT_UNSIGNED));
                strTmp = "4I" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.inputRegister(1, startlocationTmp, DataType.FOUR_BYTE_INT_SIGNED));
                strTmp = "F" + startlocationTmp.toString();
                batch.addLocator(strTmp, BaseLocator.inputRegister(1, startlocationTmp, DataType.FOUR_BYTE_FLOAT));
                startlocationTmp++;
            }
        }
        batch.setContiguousRequests(false);
        ModbusMaster master = ModbusDao.getMaster(ip);
        BatchResults<String> response = master.send(batch);
        List<Number> uiList = new ArrayList<>(); //2 byte unsigned int
        List<Number> iList = new ArrayList<>();   // 2 byte int
        List<Number> ui4List = new ArrayList<>();  //4 byte unsigned int
        List<Number> i4List = new ArrayList<>();  // 4 byte int
        List<Number> fList = new ArrayList<>();   //4 byte float
        for (i = 0; i < len; i++) {
            uiList.add((Number)response.getValue("U" + startlocation));
            iList.add((Number)response.getValue("I" + startlocation));
            ui4List.add((Number)response.getValue("4U" + startlocation));
            i4List.add((Number) response.getValue("4I" + startlocation));
            fList.add((Number) response.getValue("F" + startlocation));
            startlocation++;
        }
        Map<String, List<Number>> map = new HashMap<>();
        map.put("uiList", uiList);
        map.put("iList", iList);
        map.put("ui4List", ui4List);
        map.put("i4List", i4List);
        map.put("fList", fList);
        return R.success(map);
    }

    @GetMapping("/getBoolBatch")
    public R<Map<String, List<Boolean>>> getBoolBatch(@RequestParam String ip, @RequestParam Integer regtype, @RequestParam Integer startlocation, @RequestParam Integer len) throws ModbusInitException, ModbusTransportException, ErrorResponseException {

        //BatchRead<Integer> , BatchResults<Integer>
        // 这2个泛型代表id；并不是从modbus协议中取回的值的类型！！  每个id对应一个保存的位置信息
        //response.getValue(startlocation)中的参数就是这个id泛型，意思是从哪个id对应的modbus位置取值
        BatchRead<Integer> batch = new BatchRead<>();

        Integer i = len;
        Integer startlocationTmp = startlocation;
        if (regtype == 1) {
            while (i-- > 0 && startlocationTmp <= 65535) {
                batch.addLocator(startlocationTmp, BaseLocator.inputStatus(1, startlocationTmp));
                startlocationTmp++;
            }
        } else if (regtype == 0) {
            while (i-- > 0 && startlocationTmp <= 65535) {
                batch.addLocator(startlocationTmp, BaseLocator.coilStatus(1, startlocationTmp));
                startlocationTmp++;
            }
        }
        batch.setContiguousRequests(false);
        ModbusMaster master = ModbusDao.getMaster(ip);
        BatchResults<Integer> response = master.send(batch);
        List<Boolean> bList = new ArrayList<>();

        for (i = 0; i < len; i++) {
            bList.add((Boolean) response.getValue(startlocation));
            startlocation++;
        }

        Map<String, List<Boolean>> map = new HashMap<>();
        map.put("bList", bList);
        return R.success(map);
    }
}
